#ifndef FLOW_H
#define FLOW_H

#include "attrs.h"
#include "spdlog/spdlog.h"

#include <fmt/core.h>
#include <iostream>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>

using fmt::format;
using fmt::print;
using nlohmann::json;
using std::string;
using std::vector;

class Flow
{
public:
    string id;        /* flow_id, {node1}-{node2}-{tos}-{dis} */
    string delay_key; /* 数据库中记录流测量时延的 key */
    uint8_t tos;      /* tos */
    uint8_t dscp;     /* |******|**| */
    uint8_t ecn;      /* | dscp |ecn| */
    uint8_t dis;      /* 是否是分离路 */
    uint8_t change;   /* 是否需要降级 */

    string src;              /* 起始节点 */
    string dst;              /* 目的节点 */
    string slice;            /* 流路由的时间片起始时刻 */
    uint32_t forward_label;  /* 由 id 构成，作为MPLS label */
    uint32_t backward_label; /* 由 id 构成，作为MPLS label */

    json route;            /* 路由信息 */
    bool every_hop;        /* 是否逐跳测量时延 */
    bool update_rule;      /* 强制重新下发流表 */
    vector<string> path;   /* 当前路由方案 */
    uint8_t cnt;           /* 超过理论时延计数 */
    uint32_t theory_delay; /* 当前路由的理论时延 */

    pthread_mutex_t flow_mutex; /* flow 所有成员的互斥锁 */

    Flow() {}

    Flow(const string &src, const string &dst,
         const uint8_t tos, const string &body, const uint8_t dis , const uint8_t change)
    {

        id = format(FLOW_ID, src, dst, tos, dis);
        delay_key = format(FLOW_E2E_DELAY, src, dst, tos);
        forward_label = mpls_label(src, dst, tos);
        backward_label = mpls_label(dst, src, tos);

        this->src = src;
        this->dst = dst;
        this->route = json::parse(body);
        this->tos = tos;
        this->dis = dis;
        this->change = change;
        this->ecn = tos & 0x3;
        this->dscp = tos >> 2;

        spdlog::info("添加业务流，FLOW_ID: {0} key: {1} forward_label: {2} backward_label: {3}",
                     id, delay_key, forward_label, backward_label);

        every_hop = false;
        update_rule = true; /* 新添加的流都要求马上更新时隙 */
        pthread_mutex_init(&flow_mutex, NULL);
        theory_delay = 0;
        cnt = 0;
    }

    int mpls_label(const string &src, const string &dst, uint32_t tos)
    {
        uint32_t label = 0;
        label = (hostid(src) << 8) | hostid(dst);
        label = (label << 3) | tos;
        return label;
    }

    int hostid(const string &id)
    {
        return (stoi(id.substr(0, 2)) - 10) * 11 + stoi(id.substr(2));
    }
};

#endif
